package com.lyx.question.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lyx.common.constant.ChapterConstant;
import com.lyx.common.constant.RedisContant;
import com.lyx.common.exception.BusinessException;
import com.lyx.common.exception.ExceptionEnum;
import com.lyx.common.utils.JwtUtils;
import com.lyx.common.utils.TreeUtil;
import com.lyx.question.dto.Indexchapter;
import com.lyx.question.dto.ThreeChapterInfo;
import com.lyx.question.entity.*;
import com.lyx.question.mapper.SubjectMapper;
import com.lyx.question.service.SubjectService;
import com.lyx.question.vo.ChildrenVo;
import com.lyx.question.vo.OneSubjectVo;
import io.jsonwebtoken.lang.Collections;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 14667
 * @date 2022/7/20 10:52
 */
@Component
public class SubjectServiceImpl extends ServiceImpl<SubjectMapper, Subject> implements SubjectService {
    @Autowired
    StringRedisTemplate redisTemplate;
    @Override
    public List<OneSubject> listWithTree() {
        //先查询出所有的数据
        List<Subject> subjects = baseMapper.selectList(null);
        System.out.println(subjects);
        List<OneSubject> collect = subjects.stream().filter(subject -> subject.getParentId() == 0)
                .map(subject -> {
                    OneSubject oneSubject = new OneSubject();
                    BeanUtils.copyProperties(subject, oneSubject);
                    //利用二级分类的parentid等于一级分类的id封装一级分类的二级分类
                    oneSubject.setChildren(getChildren(oneSubject, subjects));
                    //这里这样处理是因为前端想通过null判断
                    if(oneSubject.getChildren().size()==0){
                        oneSubject.setChildren(null);
                    }
                    return oneSubject;
                }).collect(Collectors.toList());
        return collect;
    }

    @Override
    public boolean addChapter(OneSubjectVo subjectVo) {
        //这里的subjectVo已经通过数据校验，所以传到这里的数据一定是满足要求的
        //这里的添加章节是添加的一级章节，下面的查询是为了判断同级下是否有相同名字的章节
        List<Subject> chapterName = baseMapper.selectList(new QueryWrapper<Subject>().eq("chapter_name", subjectVo.getChapterName()).eq("parent_id",0));
        if (!Collections.isEmpty(chapterName)){
            throw new BusinessException(ExceptionEnum.CHAPTER_EXIST);
        }
        //删除缓存
        redisTemplate.delete(RedisContant.INDEX_CHAPTER_CACHE);

        Subject subject = new Subject();
        BeanUtils.copyProperties(subjectVo,subject);
        subject.setChapterType(ChapterConstant.ONE_SUBJECT_TYPE);
        subject.setParentId(0);
        int insert = baseMapper.insert(subject);
        return insert>0;
    }

    @Override
    public Boolean addChildChapter(ChildrenVo childrenVo) {
        //这里传过来的数据已经通过了数据校验
        Subject one = baseMapper.selectOne(new QueryWrapper<Subject>().eq("id", childrenVo.getParentId()));
        //这里的parentId就是当前要添加子类的章节id
        if(Objects.isNull(one)){
            throw new BusinessException(ExceptionEnum.NOT_EXIST.getCode(),String.format(ExceptionEnum.NOT_EXIST.getMsg(),"父章节"));
        }
        List<Subject> chapterName = baseMapper.selectList(new QueryWrapper<Subject>().eq("chapter_name", childrenVo.getChapterName()).eq("parent_id",childrenVo.getParentId()));
        //这里是为了避免同级下面有重复的名字
        if (!Collections.isEmpty(chapterName)){
            throw new BusinessException(ExceptionEnum.CHAPTER_EXIST);
        }
        //删除缓存
        redisTemplate.delete(RedisContant.INDEX_CHAPTER_CACHE);

        Subject subject = new Subject();
        subject.setChapterName(childrenVo.getChapterName());
        subject.setShowStatus(childrenVo.getShowStatus());
        //子章节的章节类型就是父章节类型加1
        subject.setChapterType(one.getChapterType()+1);
        subject.setParentId(childrenVo.getParentId());
        int insert = baseMapper.insert(subject);
        //如果其为打开状态，但其父类为关闭状态，递归的打开
        if(subject.getShowStatus().equals(1)){
            //根据当前chapter_id查找其所有的父类id
            while(subject.getParentId()!=0){
                subject = baseMapper.selectOne(new QueryWrapper<Subject>().eq("id", subject.getParentId()));
                if(subject.getShowStatus().equals(0)){
                    subject.setShowStatus(1);
                    baseMapper.updateById(subject);
                }
            }
        }
        return insert>0;
    }

    @Override
    public boolean deleteChapter(Integer id) {
        if(Objects.isNull(id)){
            throw new BusinessException(ExceptionEnum.IS_NOT_NULL.getCode(),String.format(ExceptionEnum.IS_NOT_NULL.getMsg(),"id"));
        }
        Subject subject = baseMapper.selectById(id);
        if(Objects.isNull(subject)){
            throw new BusinessException(ExceptionEnum.NOT_EXIST.getCode(),String.format(ExceptionEnum.NOT_EXIST.getMsg(),"章节"));
        }
        //删除缓存
        redisTemplate.delete(RedisContant.INDEX_CHAPTER_CACHE);

        ArrayList<Integer> ids = new ArrayList<>();
        ids.add(id);
        //这里应该是级联删除子节点
        List<Subject> subjects = baseMapper.selectList(new QueryWrapper<Subject>().eq("parent_id", id));
        getIdsByCascade(subjects,ids);
        int i = baseMapper.deleteBatchIds(ids);
        return i>0;
    }
    void getIdsByCascade(List<Subject> subjects,List<Integer> ids){
        if (Collections.isEmpty(subjects)){
            return;
        }
        subjects.stream().forEach(subject1 -> {
            List<Subject> subjects1 = baseMapper.selectList(new QueryWrapper<Subject>().eq("parent_id", subject1.getId()));
            getIdsByCascade(subjects1,ids);
            ids.add(subject1.getId());
        });
    }



    @Override
    public List<Indexchapter> indexChapter() {
        //查出一级和二级章节
        //先去缓存查
        String s = redisTemplate.opsForValue().get(RedisContant.INDEX_CHAPTER_CACHE);
        if(!StringUtils.isEmpty(s)){
            List<Indexchapter> indexchapters = JSONArray.parseArray(s, Indexchapter.class);
            return indexchapters;
        }
        //缓存没有去数据库查
        List<Indexchapter> list = baseMapper.selectIndexChapterInfo();
        List<Indexchapter> indexchapters = TreeUtil.buildTree(list);
        String indexchaptersToString = JSON.toJSONString(indexchapters);
        redisTemplate.opsForValue().set(RedisContant.INDEX_CHAPTER_CACHE,indexchaptersToString,1, TimeUnit.DAYS);
        return indexchapters;
    }

    @Override
    public void show(Integer chapterId, String chapterName) {
        if(Objects.isNull(chapterId)){
            throw new BusinessException(ExceptionEnum.IS_NOT_NULL.getCode(),String.format(ExceptionEnum.IS_NOT_NULL.getMsg(),"章节id"));
        }
        Subject subject = baseMapper.selectById(chapterId);
        if (Objects.isNull(subject)){
            throw new BusinessException(ExceptionEnum.CHAPTER_NOT_EXIST);
        }
        //删除缓存
        redisTemplate.delete(RedisContant.INDEX_CHAPTER_CACHE);
        subject.setChapterName(chapterName);
        subject.setShowStatus(1);
        baseMapper.updateById(subject);
        //根据当前chapter_id查找其所有的父类id
        while(subject.getParentId()!=0){
            subject = baseMapper.selectOne(new QueryWrapper<Subject>().eq("id", subject.getParentId()));
            if(subject.getShowStatus().equals(0)){
                subject.setShowStatus(1);
                baseMapper.updateById(subject);
            }
        }

    }

    @Override
    public void close(String chapterName, Integer chapterId) {

        if(Objects.isNull(chapterId)){
            throw new BusinessException(ExceptionEnum.IS_NOT_NULL.getCode(),String.format(ExceptionEnum.IS_NOT_NULL.getMsg(),"章节id"));
        }
        Subject subject = baseMapper.selectById(chapterId);
        if (Objects.isNull(subject)){
            throw new BusinessException(ExceptionEnum.CHAPTER_NOT_EXIST);
        }
        //删除缓存
        redisTemplate.delete(RedisContant.INDEX_CHAPTER_CACHE);
        subject.setChapterName(chapterName);
        subject.setShowStatus(0);
        baseMapper.updateById(subject);
        ArrayList<Integer> ids = new ArrayList<>();
        //这里是级联获取子节点的id
        List<Subject> subjects = baseMapper.selectList(new QueryWrapper<Subject>().eq("parent_id", chapterId));
        getIdsByCascade(subjects,ids);
        if(!Collections.isEmpty(ids)){
            baseMapper.updateBatch(ids);
        }
    }

    @Override
    public List<ThreeChapterInfo> indexThreeChapterInfo(HttpServletRequest request, Integer chapterId) {
//        先从给的token中解析出id、根据id去判断token在redis中是否存在，存在的再判断是否相等
        String jwtToken = request.getHeader("token");
        String id = JwtUtils.getMemberIdByJwtTokenIndex(request);
        Integer userId = null;
        if(!id.equals("")){
            userId = Integer.parseInt(id);
            String s = redisTemplate.opsForValue().get(String.format(RedisContant.TOKEN, userId));
            if(!jwtToken.equals(s)){
                userId = null;
            }
        }
        List<ThreeChapterInfo> list = null;
        if(Objects.isNull(userId)){
            list = baseMapper.getThreeChapterInfo(chapterId);
        }else{
            list = baseMapper.getThreeChapterInfoById(chapterId,userId);
        }
        return list;
    }


    private List<OneSubject> getChildren(OneSubject oneSubject,List<Subject> subjects){
        List<OneSubject> collect = subjects.stream().filter(subject -> subject.getParentId().equals(oneSubject.getId()))
                .map(subject -> {
                    OneSubject oneSubject1 = new OneSubject();
                    BeanUtils.copyProperties(subject, oneSubject1);
                    oneSubject1.setChildren(getChildren(oneSubject1,subjects));
                    if(oneSubject1.getChildren().size()==0){
                        oneSubject1.setChildren(null);
                    }
                    return oneSubject1;
                }).collect(Collectors.toList());
        return collect;
    }
}
